package ru.ifmo.croak.impl.remoting.query.team3;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import ru.ifmo.croak.api.Message;
import ru.ifmo.croak.api.MessageListener;
import ru.ifmo.croak.api.MessageQuery;
import ru.ifmo.croak.api.QueryRequest;
import ru.ifmo.croak.api.QueryService;
import ru.ifmo.croak.impl.remoting.query.team3.client.QueryServiceImpl;
import ru.ifmo.croak.impl.remoting.query.team3.server.QueryServerMain;

import javax.management.Query;
import javax.xml.bind.Unmarshaller;

/**
 * <p>
 * This class wraps {@link MessageQuery} which is received from the server-side.
 * It delegates all its methods to this remote query.
 * </p>
 * 
 * <p>
 * It immediately constructs with null query, which is expected to be
 * initialized later by the server.
 * </p>
 * 
 * @author Arina Afanasyeva
 */
public class RemoteMessageQueryImpl implements RemoteMessageQuery, MessageQuery {

	private volatile MessageQuery query;
	private final QueryRequest request;
    private MessageListener listener;
    private Future<ServerQuery> serverQuery;

    /**
	 * Immediately constructs with null query, which is expected to be
	 * initialized later by the server using the given request.
	 * 
	 * @param request
	 *            the given request
	 */
	public RemoteMessageQueryImpl(final QueryServiceImpl parent, QueryRequest request) {
		this.request = request;

        this.serverQuery = parent.getExecutor().submit(new Callable<ServerQuery>() {
            @Override
            public ServerQuery call() throws Exception {
                return parent.createServerQuery(RemoteMessageQueryImpl.this);
            }
        });
	}

	@Override
	public void close() {
        this.listener = null;

        try {
            ServerQuery q = serverQuery.get();
            q.close();
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (ExecutionException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (RemoteException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

	@Override
	public List<Message> getMessages() {
        try {
		    ServerQuery q = serverQuery.get();
            return Arrays.asList(q.getMessages());
        } catch (RemoteException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (ExecutionException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        
        return null;
    }

    @Override
	public void setMessageListener(MessageListener listener) {
        this.listener = listener;
	}
    
	@Override
	public QueryRequest getRequest() {
		return request;
	}

    @Override
    public void messageAvailable(Message message) throws RemoteException {
        if (listener != null) {
            listener.messageAvailable(message);
        }
    }
}
